package site.ruyi.devclient.util;

import java.io.Closeable;
import java.io.IOException;
import java.util.Properties;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

public class FTPUtil implements Closeable{

	private FTPClient ftpClient;
	private ChannelSftp channelSftp;

    private enum FtpType{
        FTP,SFTP
    }

    @FunctionalInterface
    public static interface FTPExecTemplate{
        void exec(FTPClient ftpClient) throws Exception;
    }

    @FunctionalInterface
    public static interface SFTPExecTemplate{
        void exec(ChannelSftp channelSftp) throws Exception;
    }

    private FtpType ftpType;
	private String hostname;
    private Integer port;
    private String username;
    private String password;

    public FtpType getFtpType() {
		return ftpType;
	}

	public void setFtpType(FtpType ftpType) {
		this.ftpType = ftpType;
	}

	public String getHostname() {
		return hostname;
	}

	public void setHostname(String hostname) {
		this.hostname = hostname;
	}

	public Integer getPort() {
		return port;
	}

	public void setPort(Integer port) {
		this.port = port;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}


    public FTPUtil(FtpType ftpType,String hostname,int port,String username,String password){
        this.ftpType=ftpType;
        this.hostname=hostname;
        this.port=port;
        this.username=username;
        this.password=password;

        if(FtpType.FTP.equals(ftpType)){
        	FTPClient ftpClient=new FTPClient();
            try {
                ftpClient.connect(hostname,port);
                ftpClient.enterLocalPassiveMode();
                if(!ftpClient.login(username,password)){
                	throw new RuntimeException("登录失败！");
                }

                //使用字节流传输防止出现二进制文件传输损坏
    		    ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

    		    this.ftpClient=ftpClient;
            } catch (Exception e) {
            	if(ftpClient!=null){
            		try {
						ftpClient.disconnect();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
            	}
                throw new RuntimeException(e);
            }
        }else if(FtpType.SFTP.equals(ftpType)){
        	Session sshSession = null;
            Channel channel = null;
            ChannelSftp channelSftp = null;
            try {
                JSch jsch = new JSch();
                sshSession = jsch.getSession(username, hostname, port);
                sshSession.setPassword(password);

                Properties sshConfig = new Properties();
                sshConfig.put("StrictHostKeyChecking", "no");
                sshSession.setConfig(sshConfig);
                sshSession.connect(6000);

                channel = sshSession.openChannel("sftp");
                channel.connect();
                channelSftp = (ChannelSftp)channel;
                this.channelSftp = channelSftp;
            } catch (Exception e) {
            	if(channelSftp!=null){
                    channelSftp.disconnect();
                }
                if(channel!=null){
                    channel.disconnect();
                }
                if(sshSession!=null){
                    sshSession.disconnect();
                }
                throw new RuntimeException(e);
            }
        }
    }

    public static FTPUtil getFTPClient(String hostname,int port,String username,String password){
        return new FTPUtil(FtpType.FTP,hostname,port,username,password);
    }

    public static FTPUtil getSFTPChannel(String hostname,int port,String username,String password){
        return new FTPUtil(FtpType.SFTP,hostname,port,username,password);
    }

    public void run(FTPExecTemplate ftpExecTemplate){
        if(!FtpType.FTP.equals(this.ftpType)){
            throw new UnsupportedOperationException();
        }

        try {
			ftpExecTemplate.exec(ftpClient);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
    }

    public void run(SFTPExecTemplate sftpExecTemplate){
        if(!FtpType.SFTP.equals(this.ftpType)){
            throw new UnsupportedOperationException();
        }

        try {
			sftpExecTemplate.exec(channelSftp);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
    }

	@Override
	public void close() throws IOException {
		try{
			if(ftpClient!=null){
				ftpClient.disconnect();
			}
			if(channelSftp!=null){
				channelSftp.disconnect();
				try {
					if(channelSftp.getSession().isConnected()){
						channelSftp.getSession().disconnect();
					}
				} catch (JSchException e) {
					e.printStackTrace();
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}
